#include "stdafx.h"
#include "primitive_datatypes.h"
#include "Vector.h"

//##########################################################
Vec2::Vec2():
	_x(0),
	_y(0)
{
}
//##########################################################
Vec2::Vec2(Number xy):
	_x(xy),
	_y(xy)
{
}
//##########################################################			
Vec2::Vec2(Int xy):
	_x((Number)xy),
	_y((Number)xy)
{
}
//##########################################################
Vec2::Vec2(Number x,Number y):
	_x(x),
	_y(y)
{
}
//##########################################################
Vec2::Vec2(Int x, Int y):
	_x((Number)x),
	_y((Number)y)
{
}
//##########################################################
Vec2::Vec2(const Vec2& old):
	_x(old._x),
	_y(old._y)
{
}
//##########################################################
Inline
Vec2& Vec2::operator = (const Vec2& old){
	this->_x = old._x;
	this->_y = old._y;

	return *this;
}
//##########################################################
Inline
Vec2& Vec2::operator += ( Const Vec2& other){
	this->_x += other._x;
	this->_y += other._y;

	return *this;
}
//##########################################################
Inline
Vec2& Vec2::operator -= ( Const Vec2& other){
	this->_x -= other._x;
	this->_y -= other._y;

	return *this;
}
//##########################################################
Inline
Vec2& Vec2::operator *= ( Number scalar){
	this->_x *= scalar;
	this->_y *= scalar;

	return *this;
}
//##########################################################
Inline
Vec2& Vec2::operator *= ( Int scalar){
	this->_x *= scalar;
	this->_y *= scalar;

	return *this;
}
//##########################################################
Inline
Vec2& Vec2::operator /= ( Number scalar){
	this->_x /= scalar;
	this->_y /= scalar;

	return *this;
}
//##########################################################
Inline
Vec2 Vec2::operator + () const{
	return *this;
}
//##########################################################
Inline
Vec2 Vec2::operator - () const{
	return Vec2(-this->_x,-this->_y);
}
//##########################################################
Inline
Vec2 Vec2::operator + ( Const Vec2& other) const{
	return Vec2(this->_x + other._x,this->_y + other._y);
}
//##########################################################
Inline
Vec2 Vec2::operator - ( Const Vec2& other) const{
	return Vec2(this->_x - other._x,this->_y - other._y);
}
//##########################################################
Inline
Number	Vec2::operator * ( Const Vec2& other) Const{
	return this->_x * other._x + this->_y * other._y;
}
//##########################################################
Inline
Vec2 Vec2::operator * ( Number scalar)	 const{
	return Vec2(this->_x * scalar,this->_y * scalar);
}
//##########################################################
Inline
Vec2 Vec2::operator * ( Int scalar)		 const{
	return Vec2(this->_x * scalar,this->_y * scalar);
}
//##########################################################
Inline
Vec2 Vec2::operator / ( Number scalar)	 const{
	return Vec2(this->_x / scalar,this->_y / scalar);
}
//##########################################################
Inline
Vec2 Vec2::operator / ( Int scalar)		 const{
	return Vec2(this->_x / scalar,this->_y / scalar);
}
//##########################################################
Inline
Vec2 operator * ( Number scalar, Const Vec2& vec){
	return Vec2(vec._x * scalar,vec._y * scalar);
}
//##########################################################
Inline
Vec2 operator * ( Int scalar, Const Vec2& vec){
	return Vec2(vec._x * scalar,vec._y * scalar);
}
//##########################################################
Inline
Bool Vec2::operator == ( Const Vec2& other) const{
	return ((this->_x == other._x) && (this->_y == other._y)); 
}
//##########################################################
Inline
Bool Vec2::operator != ( Const Vec2& other) const{
	return ((this->_x != other._x) || (this->_y != other._y));
}
//##########################################################
Inline
Number	Vec2::length(void) Const{
	return sqrtf(this->_x * this->_x + this->_y * this->_y);
}
//##########################################################
Inline
Number	Vec2::sqrLength(void) Const{
	return (this->_x * this->_x + this->_y * this->_y);
}
//##########################################################
Inline
Vec2&	Vec2::normalize(void){
	Number InvLength = 1 / this->length();

	this->_x *= InvLength;
	this->_y *= InvLength;

	return *this;
}
//##########################################################
Inline
Vec2	Vec2::normalized(void) Const{
	Number InvLength = 1 / this->length();

	return Vec2(this->_x * InvLength,this->_y * InvLength);
}
//##########################################################
Inline
Vec2&	Vec2::negate(void){
	this->_x = -this->_x;
	this->_y = -this->_y;

	return *this;
}
//##########################################################
inline
Vec2 Vec2::negated(void) Const{
	return Vec2(-this->_x,-this->_y);
}
//##########################################################
Inline
Vec2&	Vec2::truncate(Number max){
	if(this->length() > max){
		this->normalize();
		this->operator*(max);
	}

	return *this;
}
//##########################################################
Inline
Vec2	Vec2::truncated(Number max) Const{
	if(this->length() > max)
		return this->normalized() * max;

	return *this;
}
//##########################################################
Inline
Number	Vec2::distance(Const Vec2& other) Const{
	return (this->operator-(other)).length();
}
//##########################################################
Inline
Number	Vec2::dotProduct(Const Vec2& other) Const{
	return this->operator*(other);
}
//##########################################################
Inline
Number Vec2::cosine(Const Vec2& other) Const{
	return this->operator*(other) / (this->length() * other.length());
}
//##########################################################
Inline
Number	Vec2::angle(Const Vec2& other) Const{
	return acosf(this->cosine(other));
}
//##########################################################
Inline
Vec2  Vec2::MaxVec(Const Vec2& vec1,Const Vec2 vec2){
	return Vec2(vec1._x > vec2._x ? vec1._x : vec2._x,vec1._y > vec2._y ? vec1._y : vec2._y);
}
//##########################################################
Inline
Vec2  Vec2::MinVec(Const Vec2& vec1,Const Vec2 vec2){
	return Vec2(vec1._x < vec2._x ? vec1._x : vec2._x,vec1._y < vec2._y ? vec1._y : vec2._y);
}
//##########################################################
Inline
Vec2  Vec2::Reflect(Const Vec2& vSource,Const Vec2& vNormal){
	Vec2 result(vSource);

	Number fDotSourceNormal = vSource * vNormal;

	Vec2 vNegatedNormal = -vNormal;

	result += 2.0f * fDotSourceNormal * vNegatedNormal;

	return result;
}
//##########################################################
Vec2  Vec2::Lerp(Const Vec2& vFrom,Const Vec2& vTo,Number fPercentage){
	assert(fPercentage <= 1 && fPercentage >= 0);
	
	Number fOneMinusPercentage = 1 - fPercentage;

	return Vec2(vFrom._x * fOneMinusPercentage + vTo._x * fPercentage,vFrom._y * fOneMinusPercentage + vTo._y * fPercentage);
}
//##########################################################
Vec2  Vec2::CatmullRom(Const Vec2& vP0,Const Vec2& vP1,Const Vec2& vP2,Const Vec2& vP3,Number fPercentage){

	assert(fPercentage >= 0 && fPercentage <= 1);

	Vec2 vResult;
	Vec2 vTangent1;
	Vec2 vTangent2;
	Number fFactor2;
	Number fFactor3;

	fFactor2 = fPercentage * fPercentage;
	fFactor3 = fFactor2 * fPercentage;

	vTangent1 = (vP2 - vP0) * 0.5f;
	vTangent2 = (vP3 - vP1) * 0.5f;

	Number fTemp;

	fTemp = 3 * fFactor2 - 2 * fFactor3;
	vResult = vP2 * fTemp;
	fTemp = 1 - fTemp;
	vResult += vP1 * fTemp;
	fTemp = fFactor3 - fFactor2;
	vResult += vTangent2 * fTemp;
	fTemp += fPercentage - fFactor2;
	vResult += vTangent1 * fTemp;

	return vResult;
}
//##########################################################
//##########################################################
//##########################################################
Vec3::Vec3():
	_x(0),
	_y(0),
	_z(0) 
{	
}
//##########################################################
Vec3::Vec3(Number xyz):
	_x(xyz),
	_y(xyz),
	_z(xyz)
{
}
//##########################################################
Vec3::Vec3(Int xyz):
	_x((Number)xyz),
	_y((Number)xyz),
	_z((Number)xyz)
{
}
//##########################################################
Vec3::Vec3(Number x,Number y,Number z):
	_x(x),
	_y(y),
	_z(z)
{
}
//##########################################################
Vec3::Vec3(Int x, Int y,int z):
	_x((Number)x),
	_y((Number)y),
	_z((Number)z)
{
}
//##########################################################

Vec3::Vec3(Const Vec3& old):
	_x(old._x),
	_y(old._y),
	_z(old._z)
{
}
//##########################################################
Inline
Vec3& Vec3::operator = (Const Vec3& old)
{
	this->_x = old._x;
	this->_y = old._y;
	this->_z = old._z;

	return *this;
}
//##########################################################
Inline
Vec3&	Vec3::operator += ( Const Vec3& other){
	this->_x += other._x;
	this->_y += other._y;
	this->_z += other._z;

	return *this;
}
//##########################################################
Inline
Vec3&	Vec3::operator -= ( Const Vec3& other){
	this->_x -= other._x;
	this->_y -= other._y;
	this->_z -= other._z;

	return *this;
}
//##########################################################
Inline
Vec3&	Vec3::operator *= ( Number scalar){
	this->_x *= scalar;
	this->_y *= scalar;
	this->_z *= scalar;

	return *this;
}
//##########################################################
Inline
Vec3&	Vec3::operator *= ( Int scalar){
	this->_x *= scalar;
	this->_y *= scalar;
	this->_z *= scalar;

	return *this;
}
//##########################################################
Inline
Vec3&	Vec3::operator /= ( Number scalar){
	this->_x /= scalar;
	this->_y /= scalar;
	this->_z /= scalar;

	return *this;
}
//##########################################################
Inline
Vec3	Vec3::operator + () Const{
	return *this;
}
//##########################################################
Inline
Vec3	Vec3::operator - () Const{
	return Vec3(-this->_x,-this->_y,-this->_z);
}
//##########################################################
Inline
Vec3	Vec3::operator + ( Const Vec3& other) Const{
	return Vec3(this->_x + other._x,this->_y + other._y, this->_z + other._z);
}
//##########################################################
Inline
Vec3	Vec3::operator - ( Const Vec3& other) Const{
	return Vec3(this->_x - other._x,this->_y - other._y,this->_z - other._z);
}
//##########################################################
Inline
Number	Vec3::operator * ( Const Vec3& other) Const{
	return this->_x * other._x + this->_y * other._y + this->_z * other._z;
}
//##########################################################
Inline
Vec3	Vec3::operator * ( Number scalar)		Const{
	return Vec3(this->_x * scalar,this->_y * scalar,this->_z * scalar);
}
//##########################################################
Inline
Vec3	Vec3::operator * ( Int scalar)		Const{
	return Vec3(this->_x * scalar,this->_y * scalar,this->_z * scalar);
}
//##########################################################
Inline
Vec3	Vec3::operator / ( Number scalar)		Const{
	return Vec3(this->_x / scalar,this->_y / scalar, this->_z / scalar);
}
//##########################################################
Inline
Vec3	Vec3::operator / ( Int scalar)		Const{
	return Vec3(this->_x / scalar,this->_y / scalar,this->_z / scalar);
}
//##########################################################
inline
Vec3 operator * ( Number scalar, Const Vec3& vec){
	return Vec3(scalar * vec._x,scalar * vec._y,scalar * vec._z);
}
//##########################################################
Inline
Vec3 operator * ( Int scalar, Const Vec3& vec){
	return Vec3(scalar * vec._x,scalar * vec._y,scalar * vec._z);
}
//##########################################################
Inline
Bool	Vec3::operator == ( Const Vec3& other) Const{
	return this->_x == other._x && this->_y == other._y && this->_z == other._z;
}
//##########################################################
Inline
Bool	Vec3::operator != ( Const Vec3& other) Const{
	return this->_x != other._x || this->_y != other._y || this->_z != other._z;
}
//##########################################################
Inline
Number	Vec3::length		(void) Const{
	return sqrtf(this->_x * this->_x + this->_y * this->_y + this->_z * this->_z);
}
//##########################################################
Inline
Number	Vec3::sqrLength	(void) Const{
	return (this->_x * this->_x + this->_y * this->_y + this->_z * this->_z);
}
//##########################################################
Inline
Vec3&	Vec3::normalize	(void){
	Number InvLength = 1 / this->length();

	this->_x *= InvLength;
	this->_y *= InvLength;
	this->_z *= InvLength;

	return *this;	
}
//##########################################################
Inline
Vec3	Vec3::normalized	(void) Const{
	Number InvLength =  1 / this->length();
	
	return Vec3(this->_x * InvLength,this->_y * InvLength,this->_z * InvLength);
}
//##########################################################
Inline
Vec3&	Vec3::negate		(void){
	this->_x = -this->_x;
	this->_y = -this->_y;
	this->_z = -this->_z;

	return *this;
}
//##########################################################
Inline
Vec3	Vec3::negated		(void) Const{
	return Vec3(-this->_x,-this->_y,-this->_z);
}
//##########################################################
Inline
Vec3&	Vec3::truncate	(Number max){
	if(this->length() > max){
		this->normalize();

		this->_x *= max;
		this->_y *= max;
		this->_z *= max;
	}

	return *this;
}
//##########################################################
Inline
Vec3	Vec3::truncated	(Number max) Const{
	if(this->length() > max)
		return this->normalized() * max;

	return *this;
}
//##########################################################
inline
Number	Vec3::distance	(Const Vec3& other) Const{
	return this->operator-(other).length();
}
//##########################################################
Inline
Number	Vec3::dotProduct	(Const Vec3& other) Const{
	return this->operator*(other);
}
//##########################################################
Inline
Vec3	Vec3::crossProduct(Const Vec3& other) Const{
	return Vec3((this->_y * other._z) - (this->_z * other._y),(this->_z * other._x) - (this->_x * other._z),(this->_x * other._y) - (this->_y * other._x));
}
//##########################################################
Inline
Number	Vec3::cosine		(Const Vec3& other) Const{
	return this->operator*(other) / (this->length() * other.length());
}
//##########################################################
Inline
Number	Vec3::angle		(Const Vec3& other) Const{
	return acosf(this->cosine(other));
}
//##########################################################
Inline
Vec3  Vec3::MaxVec(Const Vec3& vec1,Const Vec3 vec2){
	return Vec3(vec1._x > vec2._x ? vec1._x : vec2._x,vec1._y > vec2._y ? vec1._y : vec2._y,vec1._z > vec2._z ? vec1._z : vec2._z);
}
//##########################################################
Inline
Vec3  Vec3::MinVec(Const Vec3& vec1,Const Vec3 vec2){
	return Vec3(vec1._x < vec2._x ? vec1._x : vec2._x,vec1._y < vec2._y ? vec1._y : vec2._y,vec1._z < vec2._z ? vec1._z : vec2._z);
}
//##########################################################
Vec3  Vec3::Reflect(Const Vec3& vSource,Const Vec3& vNormal){
	Vec3 result(vSource);

	Number fDotSourceNormal = vSource * vNormal;

	Vec3 vNegatedNormal = -vNormal;

	result += 2.0f * fDotSourceNormal * vNegatedNormal;

	return result;
}
//##########################################################
Vec3  Vec3::Lerp(Const Vec3& vFrom,Const Vec3& vTo,Number fPercentage){
	assert(fPercentage <= 1 && fPercentage >= 0);
	
	Number fOneMinusPercentage = 1 - fPercentage;

	return Vec3(vFrom._x * fOneMinusPercentage + vTo._x * fPercentage,vFrom._y * fOneMinusPercentage + vTo._y * fPercentage,vFrom._z * fOneMinusPercentage + vTo._z * fPercentage);
}
//##########################################################
Vec3  Vec3::CatmullRom(
	Const Vec3& vP0,
	Const Vec3& vP1,
	Const Vec3& vP2,
	Const Vec3& vP3,
	Number fPercentage
){
	assert(fPercentage >= 0 && fPercentage <= 1);

	Vec3 vResult;
	Vec3 vTangent1;
	Vec3 vTangent2;
	Number fFactor2;
	Number fFactor3;

	fFactor2 = fPercentage * fPercentage;
	fFactor3 = fFactor2 * fPercentage;

	vTangent1 = (vP2 - vP0) * 0.5f;
	vTangent2 = (vP3 - vP1) * 0.5f;

	Number fTemp;

	fTemp = 3 * fFactor2 - 2 * fFactor3;
	vResult = vP2 * fTemp;
	fTemp = 1 - fTemp;
	vResult += vP1 * fTemp;
	fTemp = fFactor3 - fFactor2;
	vResult += vTangent2 * fTemp;
	fTemp += fPercentage - fFactor2;
	vResult += vTangent1 * fTemp;

	return vResult;
}
//##########################################################
//##########################################################
//########################################################## 
Inline
Vec4::Vec4():
	_x(0),
	_y(0),
	_z(0),
	_w(1)
{
}
//##########################################################
Inline
Vec4::Vec4(Number xyzw):
	_x(xyzw),
	_y(xyzw),
	_z(xyzw),
	_w(xyzw)
{
}
//##########################################################
Inline
Vec4::Vec4(Int xyzw):
	_x((Number)xyzw),
	_y((Number)xyzw),
	_z((Number)xyzw),
	_w((Number)xyzw)
{
}
//##########################################################
Inline
Vec4::Vec4(Number xyz,Number w):
	_x(xyz),
	_y(xyz),
	_z(xyz),
	_w(w)
{
}
//##########################################################
Inline
Vec4::Vec4(Int xyz,Int w):
	_x((Number)xyz),
	_y((Number)xyz),
	_z((Number)xyz),
	_w((Number)w)
{
}
//##########################################################
Inline
Vec4::Vec4(Number x,Number y,Number z,Number w):
	_x(x),
	_y(y),
	_z(z),
	_w(w)
{
}
//########################################################## 
Inline
Vec4::Vec4(Int x, Int y,Int z,Int w):
	_x((Number)x),
	_y((Number)y),
	_z((Number)z),
	_w((Number)w)
{
}
//##########################################################
Inline
Vec4::Vec4(Const Vec3& old,Number w):
	_x(old._x),
	_y(old._y),
	_z(old._z),
	_w(w)
{
}
//##########################################################
Inline
Vec4::Vec4(Const Vec4& old):
	_x(old._x),
	_y(old._y),
	_z(old._z),
	_w(old._w)
{
}
//##########################################################
Vec4& Vec4::operator = (Const Vec3& old){
	this->_x = old._x;
	this->_y = old._y;
	this->_z = old._z;
	this->_w = 0;

	return *this;
}
//##########################################################
Inline
Vec4& Vec4::operator = (Const Vec4& old){
	this->_x = old._x;
	this->_y = old._y;
	this->_z = old._z;
	this->_w = old._w;

	return *this;
}
//##########################################################